~repos /only-bible-app

#kotlin#android#ios

git clone https://pyrossh.dev/repos/only-bible-app.git

The only bible app you will ever need. No ads. No in-app purchases. No distractions.



ui/src/pages/bibles/[bible]/[book]/[chapter]/index.astro



---
import fs from "fs/promises";
import Layout from "@/layouts/Layout.astro";
import Header from "@/components/Header.astro";
import ChaptersPopover from "@/components/ChaptersPopover.astro";
import { BIBLES, BOOKS } from "@/consts";
import BooksPopover from "@/components/BooksPopover.astro";
import BiblesPopover from "@/components/BiblesPopover.astro";
export async function getStaticPaths() {
const data = {};
for (const bible of BIBLES) {
const file = await fs.readFile(`${process.cwd()}/../composeApp/src/commonMain/composeResources/files/${bible.filename}`, "utf-8");
file
.split("\n")
.map((line) => line.split("|"))
.reduce((acc, item) => {
const [bookName, bookIndexStr, chapterIndexStr, verseIndex, title, text] = item;
const bookIndex = parseInt(bookIndexStr, 10);
const chapterIndex = parseInt(chapterIndexStr, 10);
const key = `${bible.version}/${bookIndexStr}/${chapterIndex + 1}`;
if (!data[key]) {
data[key] = {
params: {
bible: bible.version,
book: Object.keys(BOOKS)[bookIndex],
chapter: chapterIndex + 1,
},
props: {
localBookName: bookName,
verses: [],
},
};
}
data[key].props.verses.push({
book: bookIndex,
verse: parseInt(verseIndex, 10) + 1,
title,
text: text.trim(),
});
return acc;
}, {});
}
return Object.values(data);
}
const { bible, book, chapter } = Astro.params;
const { localBookName, verses } = Astro.props;
---
<Layout>
<Header {bible} {book} {chapter} {localBookName} />
<div id="content" class="content">
{verses.map(({ book, verse, title, text }) => (
<h2>{title && <strong set:html={title} /> <br />}</h2>
<p id={`verse-${verse}`}>
<span class="verse-no">{verse}</span>. {text}
</p>
))}
</div>
<BiblesPopover {book} {chapter} />
<BooksPopover {bible} />
<ChaptersPopover {bible} {book} />
<script is:inline define:vars={{ bible, book, chapter }}>
localStorage.setItem("last_visited", `/bibles/${bible}/${book}/${chapter}`);
const mapping = JSON.parse(localStorage.getItem(`${book}:${chapter}`) || "{}");
Object.keys(mapping).forEach((key) => {
const element = document.getElementById(`verse-${key}`);
if (element) {
element.style.backgroundColor = "var(--color-highlight-bg)";
}
});
const hammertime = new Hammer(document.getElementById("content"));
hammertime
.get("swipe")
.set({
direction: Hammer.DIRECTION_HORIZONTAL,
threshold: 100,
velocity: 0.3,
});
hammertime.on("swipeleft", function () {
const link = document.createElement("a");
link.href = `/bibles/${bible}/${book}/${parseInt(chapter, 10) + 1}`;
link.click();
});
hammertime.on("swiperight", function () {
const link = document.createElement("a");
link.href = `/bibles/${bible}/${book}/${parseInt(chapter, 10) - 1}`;
link.click();
});
</script>
</Layout>
<style>
body {
display: flex;
flex-direction: column;
flex: 1;
background-color: var(--color-body-bg);
color: var(--color-text);
font-family: var(--font-roboto);
text-rendering: optimizeLegibility;
font-variant-ligatures: common-ligatures;
font-kerning: normal;
font-size: 14pt;
line-height: 1.6;
min-height: 100vh;
@media (max-width: 720px) {
font-size: 13pt;
}
}
main {
margin-top: 1rem;
margin-bottom: 1rem;
padding-bottom: 1em;
}
.content {
display: flex;
flex-direction: column;
align-items: flex-start;
p {
font-size: 17px;
font-weight: 400;
margin: 4px 0;
}
strong {
font-weight: bold;
}
.verse-no {
font-size: 15px;
font-weight: 600;
color: var(--color-verse-no);
}
}
</style>